package com.hevs.samplewebapp.client.screens;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import com.google.gwt.cell.client.ButtonCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.cellview.client.SimplePager.Resources;
import com.google.gwt.user.cellview.client.SimplePager.TextLocation;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListDataProvider;
import com.hevs.samplewebapp.client.Patient;
import com.hevs.samplewebapp.client.bean.Category;
import com.hevs.samplewebapp.client.bean.CompositeWRefresh;
import com.hevs.samplewebapp.client.dialogbox.ConfirmDialogBox;
import com.hevs.samplewebapp.client.bean.MedicalDataItem;
import com.hevs.samplewebapp.client.dialogbox.ModifyDialogBox;
import com.hevs.samplewebapp.client.bean.Type;
import com.hevs.samplewebapp.client.services.MedicalDataServiceImpl;

/**
 * Widget to display and manage the medical data.
 *<p>It provides tools to manage data, read, delete and update them</p>
 * @author Lionel Rey, Thomas Rouvinez, Peter Schnidrig
 * @date 12.03.2012
 *
 */

public class ManageMedicalDataWidget extends CompositeWRefresh{

	// ------------------------------------------------------------
	// VARIABLES
	// ------------------------------------------------------------
	/**
	 * Dialog box to update a medical data
	 * @see ModifyDialogBox
	 */
	private ModifyDialogBox updateBox;

	/**
	 * List of medical data for the celltable
	 */
	private ListDataProvider<MedicalDataItem> medicalDataProvider;

	/**
	 * List of medical data for the patient
	 */
	private List<MedicalDataItem> medicalData;

	/**
	 * Celltable with the medical data in it
	 */
	private static CellTable<MedicalDataItem> displayDataTable;

	/**
	 * Column with the medical data date
	 */
	private TextColumn<MedicalDataItem> dateColumn;

	/**
	 * Column with the medical data type
	 */
	private TextColumn<MedicalDataItem> typeColumn;

	/**
	 * Column with the medical data value
	 */
	private TextColumn<MedicalDataItem> valueColumn;

	/**
	 * Column with the medical data category
	 */
	private TextColumn<MedicalDataItem> categoryColumn;

	/**
	 * Column with the medical data update button
	 */
	private Column <MedicalDataItem, String> update;

	/**
	 * Column with the medical data delete button
	 */
	private Column <MedicalDataItem, String> delete;

	/**
	 * Pager to go trought the list of medical data when they are above 15
	 */
	private SimplePager displayDataPager;

	/**
	 * ClientBundle that provides pager images for this widget   
	 */
	private Resources resources=GWT.create(SimplePager.Resources.class); 

	/**
	 * Date formater
	 */
	private DateTimeFormat dateFormat=DateTimeFormat.getFormat("dd.MM.yyyy"); // Default date format

	/**
	 * List of medical data from the web service
	 */
	private List<MedicalDataItem> medicalDataListRest = new ArrayList<MedicalDataItem>();

	/**
	 * Initialization of the Web service
	 */
	private static MedicalDataServiceImpl medicalDataService = new MedicalDataServiceImpl();

	// ----------------------------------------------------------------------------
	// CONSTRUCTOR
	// ----------------------------------------------------------------------------

	/**
	 * Constructor of the Manage medical data widget
	 */
	public ManageMedicalDataWidget(){
		// ------------------------------------------------------------------------
		// Widget initialization.
		// ------------------------------------------------------------------------

		// initiate widget
		initWidget(initTable());
	}

	// ----------------------------------------------------------------------------
	// METHODS
	// ----------------------------------------------------------------------------

	/**
	 * Method to generate Widget
	 * @return
	 * the widget with the list and the button to manage medical data
	 */
	private Widget initTable(){
		VerticalPanel vPanel=new VerticalPanel();

		// Create table
		displayDataTable = new CellTable<MedicalDataItem>();

		// Set Records
		medicalDataListRest = medicalDataService.getRecords();

		// ------------------------------------------------------------------------
		// Cell table with MedicalData.
		// ------------------------------------------------------------------------

		// Get the list of doctors for the current user into the table content provider.
		medicalDataProvider = new ListDataProvider<MedicalDataItem>();

		// Create the pager for the table
		displayDataPager=new SimplePager(TextLocation.CENTER,resources,false,1000,true);
		displayDataPager.setDisplay(displayDataTable);
		displayDataPager.setPageSize(10);

		// Create the date header of column.
		dateColumn = new TextColumn<MedicalDataItem>() {
			@Override
			public String getValue(MedicalDataItem medicalDataItem) {
				return medicalDataItem.getDate();
			}
		};

		// Create the type header of column.
		typeColumn = new TextColumn<MedicalDataItem>() {
			@Override
			public String getValue(MedicalDataItem medicalDataItem) {
				return Type.getFromVal(medicalDataItem.getType()).getName();
			}
		};

		// Create the value header of column.
		valueColumn = new TextColumn<MedicalDataItem>() {
			@Override
			public String getValue(MedicalDataItem medicalDataItem) {
				return medicalDataItem.getValue()+"";
			}
		};

		// Create the category header of column.
		categoryColumn = new TextColumn<MedicalDataItem>() {
			@Override
			public String getValue(MedicalDataItem medicalDataItem) {
				return Category.get(medicalDataItem.getCategory()).getName();
			}
		};

		// Create the update and delete button for every row.
		ButtonCell deleteButton= new ButtonCell();
		ButtonCell updateButton= new ButtonCell();

		update= new Column <MedicalDataItem, String>(updateButton){
			@Override
			public String getValue(MedicalDataItem medicalDataItem) {
				return "update";
			}
		};

		//listener for update button
		update.setFieldUpdater(new FieldUpdater<MedicalDataItem, String>() {
			@Override
			public void update(int index, MedicalDataItem medicalDataItem, String value) {
				updateBox = new ModifyDialogBox(medicalDataItem);
				updateBox.show();
			}
		});

		delete= new Column <MedicalDataItem, String>(deleteButton) {
			@Override
			public String getValue(MedicalDataItem medicalDataItem) {
				return "delete";
			}
		};

		//listener for delete button
		delete.setFieldUpdater(new FieldUpdater<MedicalDataItem, String>() {
			@Override
			public void update(int index, MedicalDataItem medicalDataItem, String value) {
				// Click detection for the delete button.
				askingDelete(medicalDataItem);
			}
		});

		// Make the relevant column able to sort.
		dateColumn.setSortable(true);

		// Add the columns to the cell table.
		displayDataTable.addColumn(dateColumn, "Date");
		displayDataTable.addColumn(typeColumn, "Type");
		displayDataTable.addColumn(valueColumn, "Value");
		displayDataTable.addColumn(categoryColumn, "Category");
		displayDataTable.addColumn(update, "Update");
		displayDataTable.addColumn(delete, "Delete");

		// Set columns sizes.
		displayDataTable.setColumnWidth(dateColumn, 25.0, Unit.PCT);
		displayDataTable.setColumnWidth(typeColumn, 25.0, Unit.PCT);
		displayDataTable.setColumnWidth(valueColumn, 25.0, Unit.PCT);
		displayDataTable.setColumnWidth(categoryColumn, 25.0, Unit.PCT);
		displayDataTable.setColumnWidth(update, 10.0, Unit.PCT);
		displayDataTable.setColumnWidth(delete, 10.0, Unit.PCT);

		// Set content of the table from the list of granted doctors for the current user.
		medicalDataProvider.addDataDisplay(displayDataTable);

		// Add all main layouts to the widget.
		displayDataTable.setRowCount(medicalDataListRest.size(), true);

		getData();

		refreshTable();

		vPanel.add(displayDataTable);
		vPanel.add(displayDataPager);
		vPanel.setCellHorizontalAlignment(displayDataPager,VerticalPanel.ALIGN_CENTER);

		return vPanel;
	}

	/**
	 * Method to refresh the cell table.
	 */
	public void refreshTable(){
		displayDataTable.setRowCount(0);
		getData();
		// Add the data to the data provider (filling the GUI table).
		medicalData = medicalDataProvider.getList();
		for (MedicalDataItem medicalRecord : medicalDataListRest) {
			medicalData.add(medicalRecord);
		}

		// ------------------------------------------------------------------------
		// Cell table's columns sorters.
		// ------------------------------------------------------------------------

		// date sorter listener.
		ListHandler<MedicalDataItem> dateSortHandler = new ListHandler<MedicalDataItem>(medicalData);		
		dateSortHandler.setComparator(dateColumn,new Comparator<MedicalDataItem>() {
			public int compare(MedicalDataItem m1, MedicalDataItem m2)
			{
				Date d1;
				Date d2;

				if(m1==m2)
					return 0;

				d1=dateFormat.parse(m1.getDate());
				d2=dateFormat.parse(m2.getDate());

				// Compare the dates
				if(d1!=null)
					return (d2!=null)?d1.compareTo(d2):1;
					return -1;
			}
		});

		//add sort handler
		displayDataTable.addColumnSortHandler(dateSortHandler);

		displayDataTable.setRowCount(medicalDataListRest.size(), true);
	}

	/**
	 * Method to update list of medical data in the cell Table.
	 */
	public void refreshComp(){

		medicalDataListRest = new ArrayList<MedicalDataItem>();

		//Rest call to get a list of patients
		medicalDataListRest = medicalDataService.getRecords();

		// add the data to the data provider (filling the gui table)
		medicalData = medicalDataProvider.getList();
		medicalData.clear();

		for (MedicalDataItem data : medicalDataListRest) {
			medicalData.add(data);
		}

		// ------------------------------------------------------------------------
		// Cell table's columns sorters.
		// ------------------------------------------------------------------------

		// date sorter listener.
		ListHandler<MedicalDataItem> dateSortHandler = new ListHandler<MedicalDataItem>(medicalData);		
		dateSortHandler.setComparator(dateColumn,new Comparator<MedicalDataItem>() {
			public int compare(MedicalDataItem m1, MedicalDataItem m2)
			{
				Date d1;
				Date d2;

				if(m1==m2)
					return 0;

				d1=dateFormat.parse(m1.getDate());
				d2=dateFormat.parse(m2.getDate());

				// Compare the dates
				if(d1!=null)
					return (d2!=null)?d1.compareTo(d2):1;
					return -1;
			}
		});

		//add sort handler
		displayDataTable.addColumnSortHandler(dateSortHandler);

		displayDataTable.setRowCount(medicalDataListRest.size(), true);
	}

	/**
	 * Method to get the users list from server.
	 */
	public void getData(){
		medicalDataService.sendGetAllMedicalRecords(this);
	}

	// ----------------------------------------------------------------------------
	// Pop ups creation methods.
	// ----------------------------------------------------------------------------

	/**
	 * Pop up to confirm deletion of a row in a cell table.
	 * @param medicalRecord
	 * the medical data to be deleted
	 */
	public void askingDelete(final MedicalDataItem medicalRecord){
		String title = "Deleting a record";
		String[] messages = { "You are about to delete a record, are you sure?" };

		final ConfirmDialogBox box = new ConfirmDialogBox(title, messages);

		box.show();
		box.center();
		box.addCloseHandler(new CloseHandler<PopupPanel>() {
			@Override
			public void onClose(CloseEvent<PopupPanel> event) {
				if(box.getChoice()==ConfirmDialogBox.YES){
					try {
						medicalDataService.sendDELETE(Patient.JSON_URL_MEDICALDATA_DEL, createJsonWithKey(medicalRecord));

						//get new data
						getData();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		});
	}

	/**
	 * Pop up to confirm updating of a row in a cell table.
	 * @param medicalRecord
	 * the medical data to be updated
	 */
	public void askingUpdate(final MedicalDataItem medicalRecord){
		String title = "Update a record";
		String[] messages = { "You are about to update a record, are you sure?" };

		final ConfirmDialogBox box = new ConfirmDialogBox(title, messages);

		box.show();
		box.center();
		box.addCloseHandler(new CloseHandler<PopupPanel>() {
			@Override
			public void onClose(CloseEvent<PopupPanel> event) {
				if(box.getChoice()==ConfirmDialogBox.YES){
					try {
						medicalDataService.sendPUT(Patient.JSON_URL_MEDICALDATA, createJsonWithKey(medicalRecord));

						//get new data
						getData();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		});
	}


	// ----------------------------------------------------------------------------
	// Data methods.
	// ----------------------------------------------------------------------------

	/**
	 * Method to create a medical Data Record in JSON format
	 * @param medicalRecord
	 * the medical data to be updated
	 * @return
	 * the medical data in JSON format
	 */
	private JSONObject createJsonWithKey(MedicalDataItem medicalRecord){
		//create Json
		JSONObject medicalData = new JSONObject();
		// fill JSONObject with updated medical data
		medicalData.put("value", new JSONNumber(medicalRecord.getValue()));
		medicalData.put("date", new JSONString(medicalRecord.getDate()));
		medicalData.put("category", new JSONNumber(medicalRecord.getCategory()));
		medicalData.put("type",new JSONNumber(medicalRecord.getType()));
		medicalData.put("key",new JSONString(medicalRecord.getId()));
		return medicalData;
	}
}
